package com.qishenyuan.competition.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qishenyuan.competition.constant.RedisKey;
import com.qishenyuan.competition.constant.UserConstant;
import com.qishenyuan.competition.dto.UserLoginReq;
import com.qishenyuan.competition.dto.UserUpdateInfo;
import com.qishenyuan.competition.exception.BusinessErrorType;
import com.qishenyuan.competition.exception.BusinessException;
import com.qishenyuan.competition.model.User;
import com.qishenyuan.competition.dao.UserDao;
import com.qishenyuan.competition.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qishenyuan.competition.utils.JacksonUtil;
import com.qishenyuan.competition.vo.UserInfoResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author qishenyuan
 * @since 2025-03-05
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {

    @Value("${wx.appId}")
    private String appId;

    @Value("${wx.appSecret}")
    private String appSecret;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserDao userDao;

    @Override
    public UserInfoResp login(UserLoginReq req){
        String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                appId,
                appSecret,
                req.getWxLoginCode()
        );
        log.info("js_code: {}", req.getWxLoginCode());
        try {
            String responseBody = restTemplate.getForObject(url, String.class);
            JsonNode jsonNode = objectMapper.readTree(responseBody);

            if (jsonNode.has("errcode")) {
                int errCode = jsonNode.get("errcode").asInt();
                String errMsg = jsonNode.get("errmsg").asText();
                log.error("微信接口返回错误: errCode={}, errMsg={}", errCode, errMsg);
                throw new BusinessException(errCode, errMsg);
            }

            String openId = jsonNode.get("openid").asText();
            String token;
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("open_id", openId);
            User existUser= baseMapper.selectOne(queryWrapper);
            if (!Objects.isNull(existUser)) {
                log.info("老用户登录, openId={}", openId);
                token = RedisKey.TOKEN_PREFIX + existUser.getUid();
                stringRedisTemplate.opsForValue().set(token, objectMapper.writeValueAsString(existUser), 7, TimeUnit.DAYS);
                return UserInfoResp.buildVo(existUser,token);
            }

            // 落库
            String uid = UUID.randomUUID().toString();
            User user = new User();
            user.setUid(uid);
            user.setOpenId(openId);
            user.setSchool(UserConstant.DEFAULT_SCHOOL);
            user.setAvatar(UserConstant.DEFAULT_AVATAR);
            user.setNickName(UserConstant.DEFAULT_NICKNAME);
            user.setMajor(UserConstant.DEFAULT_MAJOR);
            user.setCreateTime(System.currentTimeMillis());
            log.info("user login, openId: {}", openId);
            baseMapper.insertOrUpdateUser(user);

            // 7天过期
            token = RedisKey.TOKEN_PREFIX + uid;
            stringRedisTemplate.opsForValue().set(token, objectMapper.writeValueAsString(user), 7, TimeUnit.DAYS);
            return UserInfoResp.buildVo(user,token);
        } catch (Exception e) {
            throw new BusinessException(BusinessErrorType.SYSTEM_ERROR);
        }
    }

    @Override
    public UserInfoResp checkToken(String token, String uid) {
        log.info("check user token, 【uid】: {}, 【token】: {}", uid, token);
        String userStr = stringRedisTemplate.opsForValue().get(token);
        if (StringUtils.isBlank(userStr)) {
            throw new BusinessException(BusinessErrorType.INVALID_USER_TOKEN);
        }
        try{
            User user = objectMapper.readValue(userStr, User.class);
            String uidFromRedis = user.getUid();
            if (!uid.equals(uidFromRedis)) {
                throw new BusinessException(BusinessErrorType.INVALID_USER_TOKEN);
            }
            stringRedisTemplate.opsForValue().set(token, objectMapper.writeValueAsString(user), 7, TimeUnit.DAYS);
            return UserInfoResp.buildVo(user,token);
        }catch (Exception e){
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("check user token error, 【token】: {}", token, e);
            throw new BusinessException(BusinessErrorType.SYSTEM_ERROR);
        }
    }

    @Override
    public void updateUserInfo(UserUpdateInfo updateInfo) {
        log.info("update user info, 【userUpdateInfo】: {}", updateInfo);
        User user = new User();
        try {
        BeanUtils.copyProperties(updateInfo, user);
        if(updateInfo.isNewUser()){
            if(updateInfo.getNickName().isEmpty()){
                user.setNickName(UserConstant.DEFAULT_NICKNAME);
            }
            if(updateInfo.getAvatar().isEmpty()){
                user.setAvatar(UserConstant.DEFAULT_AVATAR);
            }
            if(updateInfo.getMajor().isEmpty()){
                user.setMajor(UserConstant.DEFAULT_MAJOR);
            }
            user.setProjectExperience(JacksonUtil.toJson(updateInfo.getProjectExperiences()));
            user.setEducationExperience(JacksonUtil.toJson(updateInfo.getEducationExperiences()));
            user.setInternshipExperience(JacksonUtil.toJson(updateInfo.getInternshipExperiences()));
            user.setCertificates(list2String(updateInfo.getCertificates()));
            user.setResume(updateInfo.getResume());
            user.setResumeByAi(updateInfo.getResumeByAi());
            baseMapper.insertOrUpdateUser(user);
        }else {
            UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
            if(StringUtils.isNotBlank(user.getSchool())){
                updateWrapper.set("school",user.getSchool());
            }
            if(StringUtils.isNotBlank(user.getNickName())){
                updateWrapper.set("nick_name",user.getNickName());
            }
            if(StringUtils.isNotBlank(user.getAvatar())){
                updateWrapper.set("avatar",user.getAvatar());
            }
            if(StringUtils.isNotBlank(user.getMajor())){
                updateWrapper.set("major",user.getMajor());
            }
            if(!Objects.isNull(updateInfo.getProjectExperiences())||!updateInfo.getProjectExperiences().isEmpty()){
                updateWrapper.set("project_experience",JacksonUtil.toJson(updateInfo.getProjectExperiences()));
            }
            if(!Objects.isNull(updateInfo.getEducationExperiences())||!updateInfo.getEducationExperiences().isEmpty()){
                updateWrapper.set("education_experience",JacksonUtil.toJson(updateInfo.getEducationExperiences()));
            }
            if(!Objects.isNull(updateInfo.getInternshipExperiences())||!updateInfo.getInternshipExperiences().isEmpty()){
                updateWrapper.set("internship_experience",JacksonUtil.toJson(updateInfo.getInternshipExperiences()));
            }
            if(!Objects.isNull(updateInfo.getCertificates())||!updateInfo.getCertificates().isEmpty()){
                updateWrapper.set("certificates",list2String(updateInfo.getCertificates()));
            }
            if(StringUtils.isNotBlank(updateInfo.getResume())){
                updateWrapper.set("resume",updateInfo.getResume());
            }
            if(StringUtils.isNotBlank(updateInfo.getResumeByAi())){
                updateWrapper.set("resume_by_ai",updateInfo.getResumeByAi());
            }
            updateWrapper.eq("uid",user.getUid());
            baseMapper.update(user,updateWrapper);
        }

            User updatedUser = userDao.selectByUid(updateInfo.getUid());
            String redisKey = RedisKey.TOKEN_PREFIX + updateInfo.getUid();
        stringRedisTemplate.opsForValue().set(redisKey, objectMapper.writeValueAsString(updatedUser), 7, TimeUnit.DAYS);
        }catch (Exception e){
            log.error("update user info error, 【uid】: {}, e: ", user.getUid(), e);
            throw new BusinessException(BusinessErrorType.SYSTEM_ERROR);
        }
    }

    // 把list转换成字符串
    private static String list2String(List<String> imageList) {
        StringBuilder sb = new StringBuilder();
        for (String image : imageList) {
            sb.append(image);
            sb.append(";");
        }
        return sb.toString();
    }
}
